/*!
    \copyright  Copyright (c) 2023 Qualcomm Technologies International, Ltd.\n
                All Rights Reserved.\n
                Qualcomm Technologies International, Ltd. Confidential and Proprietary.
    \version    
    \file       google_finder_sync.c
    \ingroup    google_finder
    \brief      Component handling synchronization of google finder data between peers 

*/
#ifdef INCLUDE_GOOGLE_FINDER
#include <peer_signalling.h>
#include <bt_device.h>
#include <device_list.h>
#include <task_list.h>
#include <logging.h>
#include <panic.h>
#include <stdlib.h>
#include <stdio.h>

#include "device_properties.h"
#include "google_finder_sync.h"
#include "google_finder.h"
#include "google_finder_pddu.h"
#include "google_finder_private.h"
#include "google_finder_advertiser.h"

/*! Global Instance of Google Finder Task Data */
google_finder_sync_task_data_t google_finder_sync;
extern google_finder_advert_data_t google_finder_advert;

const marshal_member_descriptor_t google_finder_beacon_time_counter_member_descriptors[] =
{
    MAKE_MARSHAL_MEMBER(google_finder_beacon_time_sync_req_t, uint32, beacon_time),
};

const marshal_type_descriptor_t marshal_type_descriptor_google_finder_beacon_time_sync_req_t = 
    MAKE_MARSHAL_TYPE_DEFINITION(google_finder_beacon_time_sync_req_t, google_finder_beacon_time_counter_member_descriptors);

const marshal_type_descriptor_t marshal_type_descriptor_google_finder_set_unwanted_tracking_req_t = 
    MAKE_MARSHAL_TYPE_DEFINITION_BASIC(google_finder_set_unwanted_tracking_req_t);

const marshal_type_descriptor_t marshal_type_descriptor_google_finder_beacon_time_sync_cfm_t =
    MAKE_MARSHAL_TYPE_DEFINITION_BASIC(google_finder_beacon_time_sync_cfm_t);

const marshal_type_descriptor_t marshal_type_descriptor_google_finder_set_unwanted_tracking_cfm_t =
    MAKE_MARSHAL_TYPE_DEFINITION_BASIC(google_finder_set_unwanted_tracking_cfm_t);

/*! X-Macro generate google finder sync marshal type descriptor set that can be passed to a (un)marshaller to initialise it.
 */
#define EXPAND_AS_TYPE_DEFINITION(type) (const marshal_type_descriptor_t *)&marshal_type_descriptor_##type,
const marshal_type_descriptor_t * const google_finder_sync_marshal_type_descriptors[NUMBER_OF_MARSHAL_OBJECT_TYPES] = {
    MARSHAL_COMMON_TYPES_TABLE(EXPAND_AS_TYPE_DEFINITION)
    MARSHAL_TYPES_TABLE_GOOGLE_FINDER_SYNC(EXPAND_AS_TYPE_DEFINITION)
};
#undef EXPAND_AS_TYPE_DEFINITION

/*! \brief Send the confirmation of synchronization to primary device

    \param synced
    \return void
 */
static void googleFinder_SyncBeaconTimeSendCfm(bool synced)
{
    if (appPeerSigIsConnected())
    {
        google_finder_beacon_time_sync_cfm_t* cfm = PanicUnlessMalloc(sizeof(google_finder_beacon_time_sync_cfm_t));
        cfm->synced = synced;
        DEBUG_LOG_V_VERBOSE("googleFinder_SyncBeaconTimeSendCfm. Send confirmation to the peer.");

        appPeerSigMarshalledMsgChannelTx(googleFinderSync_GetTask(),
                                         PEER_SIG_MSG_CHANNEL_GOOGLE_FINDER,
                                         cfm, MARSHAL_TYPE(google_finder_beacon_time_sync_cfm_t));
    }
    else
    {
        DEBUG_LOG_V_VERBOSE("googleFinder_SyncBeaconTimeSendCfm. No Peer to send to.");
    }
}

/*! \brief Send the confirmation of synchronization to primary device

    \param synced
    \return void
 */
static void googleFinder_SyncSetUnwantedTrackingCfm(bool synced)
{
    if (appPeerSigIsConnected())
    {
        google_finder_set_unwanted_tracking_cfm_t* cfm = PanicUnlessMalloc(sizeof(google_finder_set_unwanted_tracking_cfm_t));
        cfm->synced = synced;
        DEBUG_LOG_V_VERBOSE("googleFinder_SyncSetUnwantedTrackingCfm. Send confirmation to the peer.");

        appPeerSigMarshalledMsgChannelTx(googleFinderSync_GetTask(),
                                         PEER_SIG_MSG_CHANNEL_GOOGLE_FINDER,
                                         cfm, MARSHAL_TYPE(google_finder_set_unwanted_tracking_cfm_t));
    }
    else
    {
        DEBUG_LOG_V_VERBOSE("googleFinder_SyncSetUnwantedTrackingCfm. No Peer to send to.");
    }
}

/*! \brief Handle confirmation of transmission of a marshalled message.

    \param cfm confirmation of transmission of a marshalled message channel message.
    \return void
 */
static void googleFinder_SyncHandleMarshalledMsgChannelTxCfm(const PEER_SIG_MARSHALLED_MSG_CHANNEL_TX_CFM_T* cfm)
{
    DEBUG_LOG_V_VERBOSE("googleFinder_SyncHandleMarshalledMsgChannelTxCfm channel %u status %u", cfm->channel, cfm->status);
}

/*! \brief Handle incoming marshalled messages from peer google finder sync component.

    \param ind indication of incoming marshalled message channel message
    \return void
 */
static void googleFinder_SyncHandleMarshalledMsgChannelRxInd(PEER_SIG_MARSHALLED_MSG_CHANNEL_RX_IND_T* ind)
{
    switch(ind->type)
    {
        case MARSHAL_TYPE(google_finder_beacon_time_sync_req_t):
        {
            google_finder_beacon_time_sync_req_t *req = (google_finder_beacon_time_sync_req_t*)ind->msg;
            googleFinderTaskData *google_finder_task_ptr = googleFinder_GetTaskData();

            DEBUG_LOG("googleFinder_SyncHandleMarshalledMsgChannelRxInd:  Beacon time sync req.");
            google_finder_task_ptr->beacon_time_data.beacon_time = req->beacon_time;
            googleFinder_KickBeaconTimeCounter();

            /* Send confirmation to peer */
            googleFinder_SyncBeaconTimeSendCfm(TRUE);
            free(req);
        }
        break;

        case MARSHAL_TYPE(google_finder_beacon_time_sync_cfm_t):
        {
            google_finder_beacon_time_sync_cfm_t *cfm = (google_finder_beacon_time_sync_cfm_t*)ind->msg;

            if(!cfm->synced)
            {
                DEBUG_LOG_V_VERBOSE("googleFinder_SyncHandleMarshalledMsgChannelRxInd: failed to synchronize beacon time.");
            }
            else
            {
                DEBUG_LOG_V_VERBOSE("googleFinder_SyncHandleMarshalledMsgChannelRxInd: beacon time synchronized successfully.");
            }
            free(cfm);
        }
        break;

        case MARSHAL_TYPE(google_finder_set_unwanted_tracking_req_t):
        {
            DEBUG_LOG("googleFinder_SyncHandleMarshalledMsgChannelRxInd: Received Unwanted tracking protection mode.");
            google_finder_set_unwanted_tracking_req_t* req = (google_finder_set_unwanted_tracking_req_t*)ind->msg;

            if(req->unwanted_tracking_prot_mode)
            {
                GOOGLE_FINDER_FLAGS_SET_UNWANTED_TRACKING_PROTECTION_MODE(google_finder_advert.raw_flags);
            }
            else
            {
                GOOGLE_FINDER_FLAGS_RESET_UNWANTED_TRACKING_PROTECTION_MODE(google_finder_advert.raw_flags);
            }

            /* Trigger the update */
            googleFinderAdv_UpdateHashedFlagsAdvData();
            /* Send confirmation to peer */
            googleFinder_SyncSetUnwantedTrackingCfm(TRUE);
            free(req);
        }
        break;

        case MARSHAL_TYPE(google_finder_set_unwanted_tracking_cfm_t):
        {
            google_finder_set_unwanted_tracking_cfm_t *cfm = (google_finder_set_unwanted_tracking_cfm_t*)ind->msg;

            if(!cfm->synced)
            {
                DEBUG_LOG_V_VERBOSE("googleFinder_SyncHandleMarshalledMsgChannelRxInd: failed to synchronize unwanted tracking mode.");
            }
            else
            {
                DEBUG_LOG_V_VERBOSE("googleFinder_SyncHandleMarshalledMsgChannelRxInd: unwanted tracking mode synchronized successfully.");
            }
            free(cfm);
        }
        break;

        default:
        break;
    }
}

/*! \brief Google Finder Sync Message Handler
 */
static void googleFinder_SyncHandleMessage(Task task, MessageId id, Message message)
{
    UNUSED(task);

    switch (id)
    {
        /* marshalled messaging */
        case PEER_SIG_MARSHALLED_MSG_CHANNEL_RX_IND:
            DEBUG_LOG_V_VERBOSE("googleFinder_SyncHandleMessage. PEER_SIG_MARSHALLED_MSG_CHANNEL_RX_IND");
            googleFinder_SyncHandleMarshalledMsgChannelRxInd((PEER_SIG_MARSHALLED_MSG_CHANNEL_RX_IND_T*)message);
            break;
        case PEER_SIG_MARSHALLED_MSG_CHANNEL_TX_CFM:
            DEBUG_LOG_V_VERBOSE("googleFinder_SyncHandleMessage. PEER_SIG_MARSHALLED_MSG_CHANNEL_TX_CFM");
            googleFinder_SyncHandleMarshalledMsgChannelTxCfm((PEER_SIG_MARSHALLED_MSG_CHANNEL_TX_CFM_T*)message);
            break;

        default:
            break;
    }
}

/*! \brief Run beacon time counter on peer earbud once EIK is written to primary earbud.

    \param void 
    \return void
*/
void GoogleFinder_SyncBeaconTime(void)
{
    bdaddr peer_addr;
    googleFinderTaskData *google_finder_task_ptr = googleFinder_GetTaskData();

    if(appDeviceGetPeerBdAddr(&peer_addr))
    {
        DEBUG_LOG("googleFinder_SyncBeaconTime. Kick beacon time counter on peer bud.");

        google_finder_beacon_time_sync_req_t *ind = PanicUnlessMalloc(sizeof(google_finder_beacon_time_sync_req_t));
        ind->beacon_time = google_finder_task_ptr->beacon_time_data.beacon_time;

        /*! Send beacon time counter on other earbud and kick start the beacon time counter */
        appPeerSigMarshalledMsgChannelTx(googleFinderSync_GetTask(),
                                         PEER_SIG_MSG_CHANNEL_GOOGLE_FINDER,
                                         ind, MARSHAL_TYPE(google_finder_beacon_time_sync_req_t));
    }
    else
    {
        DEBUG_LOG("googleFinder_SyncBeaconTime. No Peer to send to.");
    }
}

/*! \brief Handler function to sync unwanted tracking protection mode to peer earbud.

    \param sync data
    \return void
*/
void GoogleFinder_SyncUnwantedTracking(bool is_unwanted_tracking_prot_mode)
{
    bdaddr peer_addr;
    google_finder_set_unwanted_tracking_req_t *sync_data;

    if(appDeviceGetPeerBdAddr(&peer_addr))
    {
        DEBUG_LOG("googleFinder_SyncBeaconTime. Sync Unwanted Tracking protection mode.");
        sync_data = (google_finder_set_unwanted_tracking_req_t *) PanicUnlessMalloc(sizeof(google_finder_set_unwanted_tracking_req_t));
        sync_data->unwanted_tracking_prot_mode = is_unwanted_tracking_prot_mode;

        /*! sync unwanted tracking protection mode on other earbud */
        appPeerSigMarshalledMsgChannelTx(googleFinderSync_GetTask(),
                                         PEER_SIG_MSG_CHANNEL_GOOGLE_FINDER,
                                         sync_data, MARSHAL_TYPE(google_finder_set_unwanted_tracking_req_t));
    }
    else
    {
        DEBUG_LOG("googleFinder_SyncSetUnwantedTracking. No Peer to send to.");
    }
}

void googleFinder_SyncInit(void)
{
    google_finder_sync_task_data_t *finder_sync = googleFinderSync_GetTaskData();

    /* Initialize component task data */
    memset(finder_sync, 0, sizeof(*finder_sync));
    finder_sync->task.handler = googleFinder_SyncHandleMessage;

    /* Register with peer signalling to use the google finder sync msg channel */
    appPeerSigMarshalledMsgChannelTaskRegister(googleFinderSync_GetTask(),
                                               PEER_SIG_MSG_CHANNEL_GOOGLE_FINDER,
                                               google_finder_sync_marshal_type_descriptors,
                                               NUMBER_OF_MARSHAL_OBJECT_TYPES);

    DEBUG_LOG("GoogleFinder_SyncInit. Initialized successfully. ");
}
#endif /* INCLUDE_GOOGLE_FINDER */
